package common;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import math.KurtosisBasedMethod;
import math.LeastSquareMethod;
import math.WLeastSquareMethod;
import math.common.MathCommon;
import math.probability.ExpDistribution;
import math.probability.LNormalDistribution;
import math.probability.NormalDistribution;
import math.probability.ProbDistribution;

public class TestEIVModWeight {
	
	public void compBias() {
		ProbDistribution distX = new ExpDistribution(1.0);
		ProbDistribution distEps = new NormalDistribution(0.0,0.5);
		Double xAss = 2.0;
		
		Double alpha = 5.0;
		int M = 1000;
		Double [] aSet = {0.0, 0.05, 0.1, 0.2, 0.3};
		Integer [] nSet  = {50, 100, 200, 500, 1000};
		
		for (int n : nSet) {
		for (Double a : aSet) {
			List<Double> b1 = new ArrayList<Double> ();
			List<Double> b2 = new ArrayList<Double> ();
			Random r = new Random();
			for (int i = 0; i < M; i++) {
				ProbDistribution distXi = new NormalDistribution(0.0,a/(1-a));
				StructuralModel model = new StructuralModel(n, distX, distXi, distEps, 0.0,1.0,r);
				List<Double> U = MathCommon.Normalize(model.getSmplU());
				List<Double> V = MathCommon.Normalize(model.getSmplV());


				
				List<Double> W = new ArrayList<Double> ();
				for (int j = 0; j < n; j++) 
					W.add(U.get(j) + alpha);
				b1.add(new LeastSquareMethod().estimate(V, U));
				b2.add(new WLeastSquareMethod().estimate(V, U, W));
			}
			Double m1 = 1-MathCommon.getMean(b1);
			Double m2 = 1-MathCommon.getMean(b2);
			Double m2_theor = a*alpha/(xAss*(1.0-a)+alpha);
			System.out.println(n + ";" + a + ";" + m1 + ";" + m2 + ";" + m2_theor);
		}
		}
	}
	
	public void solveProblem() {
//		ProbDistribution distX = new ExpDistribution(1.0);
		ProbDistribution distEps = new NormalDistribution(0.0,0.5);
		ProbDistribution distX = new LNormalDistribution(-Math.log(2.0)/2.0, Math.log(2.0));
		
		Double b = 1.0;
		
		Double alpha = 5.0;
		int M = 5000;
		Double [] aSet = {0.05, 0.1, 0.2, 0.3};
		Integer [] nSet  = {50, 100, 200, 500, 1000};
		
		for (int n : nSet) {
		for (Double a : aSet) {
			List<Double> oldEst = new ArrayList<Double> ();
			List<Double> newEst = new ArrayList<Double> ();
			Random r = new Random();
			for (int i = 0; i < M; i++) {
				ProbDistribution distXi = new NormalDistribution(0.0,a/(1-a));
				StructuralModel model = new StructuralModel(n, distX, distXi, distEps, 0.0,b,r);
				List<Double> U = MathCommon.Normalize(model.getSmplU());
				List<Double> V = MathCommon.Normalize(model.getSmplV());


				
				List<Double> W = new ArrayList<Double> ();
				for (int j = 0; j < n; j++) 
					W.add(U.get(j) + alpha);
				
				Double b1 = new LeastSquareMethod().estimate(V, U);
				Double b2 = new WLeastSquareMethod().estimate(V, U, W);
				Double U3 = MathCommon.getUnb3Moment(U);
				Double U2 = MathCommon.getVar(U);
				
				newEst.add(b2+alpha*U2*(b2-b1)/U3);
				oldEst.add(new KurtosisBasedMethod().estimate(V, U));
				
			}
			Double m1 = MathCommon.median(newEst);
			Double m2 = MathCommon.median(oldEst);
			Double d11 = MathCommon.quantile(newEst,0.025);
			Double d12 = MathCommon.quantile(newEst,0.975);
			Double d21 = MathCommon.quantile(oldEst,0.025);
			Double d22 = MathCommon.quantile(oldEst,0.975);
			
			System.out.printf("%d;%f;%f;%f;%f;%f;%f;%f;%f;%f;%f;%f\n",n,a,m1,d11,d12,Math.abs(m1-b)/b, (d12-d11)/2.0/b, 
															m2,d21,d22,Math.abs(m2-b)/b, (d22-d21)/2.0/b);
			
		}
		}
	}
	
	public static void main (String[] args) {
		TestEIVModWeight test = new TestEIVModWeight();
		test.solveProblem();
	}

}
